home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ADA Programming Guide
/
ADA Programming Guide.iso
/
ada_pcdp
/
adas
/
interp.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-01-30
|
20KB
|
634 lines
unit interp;
{ AdaS interpreter }
interface
uses crt,global,util;
procedure interpret;
implementation
procedure interpreter;
const
stepmax = 4; { maximum steps executed between scheduler calls }
tru = 1; { internal representation of boolean values }
fals = 0;
inactive = 999; { code for inactive process }
var
ps: (run, fin, divchk, inxchk, stkchk, redchk, deadlock);
{ processor status codes }
s: array[1..stmax] of integer;
{ the stack }
ptab: array[ptype] of { process table }
record
t: integer; { top of stack }
b: integer; { bottom of stack }
pc: integer; { program counter }
stacksize: integer; { size of stack segment }
display: array[1..lmax] of integer;
{ display of static links }
suspend: integer; { suspension pointer }
priority: integer; { priority }
timecalled: integer; { time called for entry queues }
p1, p2: integer; { parameters of entry call }
end;
ir: order; { current instruction being executed }
chrcnt: integer; { counter of characters in line }
npr: ptype; { number of active processes }
curpr: ptype; { current process }
stepcount: integer; { count of steps in this time slice }
steps: integer; { number of steps until break }
selflag: boolean; { select is being executed }
pflag: boolean; { processes being activated }
selloop: integer; { loop count in select statement }
selrandom: integer; { for random choice of alternative in select }
seltask: ptype; { task containing select statement }
deltaproc: integer; { process index increment for scheduling }
stamp: integer; { internal clock for time stamp }
curent: integer; { current entry table index }
glovar: array[1..10] of integer;
{ global variable indices for watch }
numglo: integer; { number of entries in glovar }
ch: char; { temporary variables }
h1, h2, h3, h4: integer;
function itob(i: integer): boolean;
{ integer to boolean }
begin
itob := i=tru
end;
function btoi(b: boolean): integer;
{ boolean to integer }
begin
if b then btoi := tru else btoi := fals
end;
procedure getsteps;
{ get command from break }
begin
clreol;
deltaproc := 1; { choose next active process in table }
stepcount := 0;
steps := 1; { one step before next break }
write('Command: ');
ch := readkey;
if ch = '+' then
else if ch = '*' then deltaproc := 0 { don't change process }
else if ch = '-' then steps := maxint { execute indefinitely }
else if ch = '/' then ps := fin { terminate interpretation }
else { choose number of steps }
{$I-}
repeat
write('Steps: ');
readln(steps);
until (ioresult = 0) and (steps > 0)
{$I+}
end;
procedure dump;
{ called upon break and upon abnormal termination }
var i,j: integer;
x,y: byte;
begin
x := wherex; y := wherey; { save program window coordinates }
window(1,13,40,25); { write in dump window }
writeln;
with ptab[curpr] do
write('halt in process ', curpr:1, ' ');
clreol;
case ps of
run: writeln('break');
deadlock: writeln('deadlock');
divchk: writeln('divsion by zero');
inxchk: writeln('invalid index');
stkchk: writeln('storage overflow');
redchk: writeln('reading past eof');
end;
writeln('process suspend pc instruction');
for i := 0 to pmax do
with ptab[i] do
begin
write(i:4, suspend:9, pc:5, code[pc].f:6, ' ');
printinst(output, code[pc].f);
writeln;
end;
writeln('entries');
for i := 1 to entries do
with entry[i] do
begin
write(name);
clreol;
if open <> 0 then write(' acceptor ', open:1,'/', waiting:1)
else
begin
write(' callers ');
for j := 1 to pmax do
if ptab[j].suspend = i then
write(j:1,'/',ptab[j].timecalled:1,' ')
end;
writeln
end;
getsteps; { get user command }
window(1,1,80,12); { restore program window }
gotoxy(x,y)
end;
procedure chooseproc;
{ Scheduler:
starting with highest priority, search for a process
that is not suspended, then choose a time slice }
var found: boolean;
begin
h3 := pmax; { highest priority }
h2 := (curpr + deltaproc) mod (pmax+1); { start search from here }
h1 := h2;
repeat
repeat
found := (ptab[h2].suspend = 0) and (ptab[h2].priority = h3);
h4 := h2;
h2 := (h2 + 1) mod (pmax + 1);
until found or (h2 = h1);
if not found then h3 := h3 - 1; { next lower priority }
until found or (h3 = 0);
if h3 = 0 then ps := deadlock else curpr := h4;
stepcount := random(stepmax) { choose random time slice }
end;
procedure getpriorities;
{ for each execution of the interpreter, individual priorities
may be set, otherwise all process have the same priority }
begin
write('Priorities = ');
read(h1);
if h1 <> 0 then
begin
readln(h2, h3);
ptab[1].priority := h1;
ptab[2].priority := h2;
ptab[3].priority := h3
end
end;
procedure initinterpret;
{ initialization }
var c: ptype;
i: integer;
begin
s[1] := 0; { environment activation record }
s[2] := 0;
s[3] := -1;
s[4] := btab[1].last;
with ptab[0] do { main process }
begin
b := 0;
suspend := 0; { initially active }
priority := pmax;
display[1] := 0;
t := btab[2].vsize-1;
pc := tab[s[4]].adr;
stacksize := stmax - pmax*stkincr
end;
for c := 1 to pmax do { other processes }
with ptab[c] do
begin
display[1] := 0;
pc := 0;
priority := pmax; { default priority }
suspend := inactive; { initially inactive }
b := ptab[c-1].stacksize+1;
stacksize := b+stkincr-1;
t := b-1
end;
stamp := 0;
npr := 0;
curpr := 0;
seltask := 0;
selrandom := 0;
selloop := 2;
pflag := false;
selflag := false;
stepcount := 0;
ps := run;
chrcnt := 0;
steps := 0;
numglo := 0;
for i := 1 to entries do
with entry[1] do
begin open := 0; waiting := 0 end;
for i := 1 to 10 do glovar[i] := 0;
randomize; { set random number generator }
getpriorities;
clrscr;
window(1,1,80,12); { program window }
end;
procedure relinquish(i: integer);
{ relinquish the processor by suspending on i and forcing
a call to the scheduler }
begin
ptab[curpr].suspend := i;
stepcount := 0
end;
begin { interpret }
initinterpret;
repeat
if keypressed then { pressing any key forces break }
begin ch := readkey; steps := 0 end;
if steps = 0 then dump;
steps := steps - 1;
if ptab[0].suspend = 0 then curpr := 0
{ highest priority to main program to allow activation }
else if stepcount = 0 then chooseproc
else stepcount := stepcount - 1;
with ptab[curpr] do { extract next instruction }
begin
ir := code[pc];
pc := pc + 1
end;
if pflag then { process being activated }
begin
if ir.f=18 { markstack } then npr := npr + 1;
curpr := npr
end;
with ptab[curpr] do
case ir.f of { decode instruction }
0: begin { load address }
t := t + 1;
if t > stacksize then ps := stkchk
else s[t] := display[ir.x] + ir.y
end;
1: begin { load value }
t := t + 1;
if t > stacksize then ps := stkchk
else s[t] := s[display[ir.x] + ir.y]
end;
2: begin { load indirect }
t := t + 1;
if t > stacksize then ps := stkchk
else s[t] := s[s[display[ir.x] + ir.y]]
end;
3: begin { update display }
h1 := ir.y;
h2 := ir.x;
h3 := b;
repeat
display[h1] := h3;
h1 := h1 - 1;
h3 := s[h3+2]
until h1 = h2
end;
4: pflag := true; { cobegin - activate processes }
5: begin { coend - all processes activated }
pflag := false;
ptab[0].suspend := inactive
end;
6: begin { semaphore wait }
h1 := s[t];
t := t - 1;
if s[h1] > 0 then s[h1] := s[h1] - 1 else relinquish(h1)
end;
7: begin { semaphore signal }
h1 := s[t];
t := t - 1;
h2 := pmax+1;
h3 := random(h2); { from random point }
while (h2 >= 0) and (ptab[h3].suspend <> h1) do
begin { search for process suspended on this semaphore }
h3 := (h3+1) mod (pmax+1);
h2 := h2 - 1
end;
if h2 < 0 then s[h1] := s[h1] + 1 { if none then increment }
else ptab[h3].suspend := 0 { release suspended process }
end;
10: pc := ir.y; { jump }
11: begin { conditional jump }
if s[t] = fals then pc := ir.y;
t := t - 1
end;
14: begin { top of for loop }
h1 := s[t-1]; { lower bound on index }
if h1 <= s[t] then s[s[t-2]] := h1 else
begin { upper > lower so skip loop }
t := t - 3;
pc := ir.y
end
end;
15: begin { bottom of for loop }
h2 := s[t-2]; { upper bound }
h1 := s[h2] + 1; { index }
if h1 <= s[t] then
begin { jump to top }
s[h2] := h1;
pc := ir.y
end
else t := t - 3 { finished }
end;
18: begin { mark stack }
h1 := btab[tab[ir.y].ref].vsize; { size of stack for call }
if t+h1 > stacksize then ps := stkchk else
begin
t := t + 5; { allocate room for activation record }
s[t-1] := h1 - 1; { store size and tab index }
s[t] := ir.y { for call instruction }
end
end;
{ actual parameters stacked between mark stack and call }
19: begin { procedure call }
suspend := 0;
h1 := t - ir.y; { old bottom of stack }
h2 := s[h1+4]; { tab index left by mark stack }
h3 := tab[h2].lev; { get nesting level }
display[h3+1] := h1; { store in display }
h4 := s[h1+3] + h1; { stack size left by mark stack }
s[h1+1] := pc; { return address }
s[h1+2] := display[h3]; { static link }
if pflag then s[h1+3] := ptab[0].b else s[h1+3] := b;
{ dynamic link }
for h3 := t+1 to h4 do s[h3] := 0;
{ zero local variables }
b := h1; { new bottom of stack }
t := h4; { new top of stack }
pc := tab[h2].adr { start of procedure code }
end;
21: begin { load array element given index }
h1 := ir.y;
h2 := atab[h1].low;
h3 := s[t];
if h3 < h2 then ps := inxchk else
begin
t := t - 1;
s[t] := s[t] + (h3-h2) * atab[h1].elsize
end
end;
24: begin { literal }
t := t + 1;
if t > stacksize then ps := stkchk else s[t] := ir.y
end;
27: begin { read }
if eof(inp) then ps := redchk else
case ir.y of
1: read(inp, s[s[t]]);
3: begin read(inp, ch); s[s[t]] := ord(ch) end
end;
t := t - 1
end;
28: begin { write string }
h1 := s[t];
h2 := ir.y;
t := t - 1;
chrcnt := chrcnt + h1;
if chrcnt = 80 then begin writeln; chrcnt := 0 end;
repeat
write(stab[h2]);
h1 := h1 - 1;
h2 := h2 + 1
until h1 = 0
end;
29: begin { write1 }
if ir.y = 3 then h1 := 1 else h1 := 10;
chrcnt := chrcnt + h1;
if chrcnt = 80 then begin writeln; chrcnt := 0 end;
case ir.y of
1: write(s[t]);
2: write(itob(s[t]));
3: if (s[t]<0) or (s[t]>255) then ps := inxchk
else write(chr(s[t]))
end;
t := t - 1
end;
31: { end of program } ps := fin;
32: { exit procedure } begin
t := b - 1; { old top of stack }
pc := s[b+1]; { return address }
if pc <> 0 then b := s[b+3] else
{ old bottom of stack from dynamic link }
begin { exit from process }
if selflag then ptab[seltask].suspend := 0;
selloop := 2;
relinquish(inactive); { deactivate process }
npr := npr - 1; { one less process active }
if npr=0 then ptab[0].suspend := 0
{ if last process, reactivate main }
end
end;
34: s[t] := s[s[t]]; { from address get value, used with index }
35: s[t] := btoi(not(itob(s[t]))); { boolean not }
36: s[t] := - s[t]; { unary minus }
38: begin { store }
if ir.y <> 0 then { watch variable }
begin
h1 := wherex; h2 := wherey; { save program window }
window(41,13,80,25); { watch window }
h4 := numglo + 1; { see if variable exists in table }
for h3 := 1 to numglo do
if ir.y = glovar[h3] then
h4 := h3;
if h4 = numglo+1 then { create new table entry }
begin
numglo := h4;
glovar[numglo] := ir.y
end;
gotoxy(1,h4+1); { table index is line in window }
writeln(tab[ir.y].name, s[t]:8);
window(1,1,80,12); { reset window }
gotoxy(h1,h2)
end;
s[s[t-1]] := s[t];
t := t - 2;
end;
{ arithmetical and logical operators }
45: begin t:=t-1; s[t] := btoi(s[t] = s[t+1]) end;
46: begin t:=t-1; s[t] := btoi(s[t] <> s[t+1]) end;
47: begin t:=t-1; s[t] := btoi(s[t] < s[t+1]) end;
48: begin t:=t-1; s[t] := btoi(s[t] <= s[t+1]) end;
49: begin t:=t-1; s[t] := btoi(s[t] > s[t+1]) end;
50: begin t:=t-1; s[t] := btoi(s[t] >= s[t+1]) end;
51: begin t:=t-1; s[t] := btoi(itob(s[t]) or itob(s[t+1])) end;
52: begin t:=t-1; s[t] := s[t] + s[t+1] end;
53: begin t:=t-1; s[t] := s[t] - s[t+1] end;
56: begin t:=t-1; s[t] := btoi(itob(s[t]) and itob(s[t+1])) end;
57: begin t:=t-1; s[t] := s[t] * s[t+1] end;
58: begin
t := t - 1;
if s[t+1] = 0 then ps := divchk else
s[t] := s[t] div s[t+1]
end;
59: begin
t := t - 1;
if s[t+1] = 0 then ps := divchk else
s[t] := s[t] mod s[t+1]
end;
62: { readln } if eof(inp) then ps := redchk else readln(inp);
63: { writeln } begin writeln; chrcnt := 0 end;
{ Before an entry call, the parameters are compiled
and the appropriate instruction 70-73 is emitted.
in parameters load the value into the fields p1, p2
of the calling process table entry while out
parameters load the address into those fields }
70: begin p1 := s[t]; t := t - 1 end; { load in parm 1 }
71: begin p2 := s[t]; t := t - 1 end; { load in parm 2 }
72: p1 := display[ir.x]+ir.y; { load out parm 1 }
73: p2 := display[ir.x]+ir.y; { load out parm 2 }
74: begin { call entry }
stamp := stamp + 1; { time stamp this call }
timecalled := stamp;
with entry[ir.y] do
if open <> 0 then { there is a waiting accept }
with ptab[waiting] do { waiting contains the process }
begin { index of the accepting task }
pc := open; { open contains the pc of the accept }
open := 0; { revoke wait status }
suspend := 0; { reactivate accepting task }
waiting := curpr { store calling index here }
end
else { no waiting accept }
if waiting = 0 then waiting := curpr;
{ if no other calls, we are first on this entry queue }
if selflag then ptab[seltask].suspend := 0;
{ reactivate task with select }
selloop := 2;
relinquish(ir.y); { calling task always suspended }
end;
{ A select statement will try each accept statement in
turn to see if there is a waiting call, otherwise it
will suspend itself.
To implement random selection of an alternative,
a random number is used to decide if the first accept
statement should be skipped. Since the second accept
statement may be closed or have an empty queue,
two passes are taken around the select loop before
deciding to suspend. }
75: begin { accept entry }
curent := ir.y;
with entry[ir.y] do
if waiting = 0 then { if no entry call waiting }
if selflag then { executing select }
begin
pc := ir.x; { jump over accept body }
selloop := selloop - 1
end
else { no select }
begin
open := pc; { note pc of waiting accept }
waiting := curpr; { and accepting process index }
relinquish(ir.y); { suspend pending an entry call }
end
else if selflag and (selrandom > 0) then
begin
pc := ir.x; { randomly jump over accept body }
selrandom := 0
end
end;
{ When entering rendezvous, copy in parameters (76-77)
from calling task's process table fields p1 and p2.
When completing rendezvous, use addresses in those
fields to copy back the values (78-79). }
76: s[display[ir.x]+ir.y] := ptab[entry[curent].waiting].p1;
77: s[display[ir.x]+ir.y] := ptab[entry[curent].waiting].p2;
78: s[ptab[entry[curent].waiting].p1] := s[display[ir.x]+ir.y];
79: s[ptab[entry[curent].waiting].p2] := s[display[ir.x]+ir.y];
80: begin { release call }
h1 := ir.y;
with entry[h1] do
begin
ptab[waiting].suspend := 0; { calling task reactivated }
h4 := maxint; { earliest call becomes waiting call }
h3 := 0;
for h2 := 1 to pmax do
if (ptab[h2].suspend = h1) and
(ptab[h2].timecalled < h4) then
begin
h4 := ptab[h2].timecalled;
h3 := h2
end;
waiting := h3
end
end;
81: begin { select }
selflag := true; { select being executed }
selrandom := random(2); { random choice of alternative }
selloop := 2; { loop count }
seltask := curpr { process executing select }
end;
82: { terminate }
if npr = 1 then selflag := false { last process so terminate }
else pc := pc + 1; { skip over exit instruction }
83: { end select } if selloop = 0 then relinquish(inactive)
{ after twice around loop we can suspend }
end { case };
until ps <> run;
writeln;
if ps <> fin then dump
end;
procedure interpret;
{ Interpret the program in the code table }
var ch: char;
begin
repeat
write('Interpret (y/n): ');
if eoln then readln;
readln(ch);
if ch = 'y' then interpreter
until ch <> 'y';
window(1,1,80,25);
clrscr
end;
end.